package org.nlp.algo.hash.ConsistencyHash;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;

public class ConsistentHash<T> {

 private final HashFunction hashFunction;
 private final int numberOfReplicas;
 private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>();

 public ConsistentHash(HashFunction hashFunction, int numberOfReplicas,
     Collection<T> nodes) {
   this.hashFunction = hashFunction;
   this.numberOfReplicas = numberOfReplicas;

   for (T node : nodes) {
     add(node);
   }
 }

 public void add(T node) {
   for (int i = 0; i < numberOfReplicas; i++) {
                circle.put(hashFunction.hashString(node.toString() + i).asInt(), node);
   }
 }

 public void remove(T node) {
   for (int i = 0; i < numberOfReplicas; i++) {
     circle.remove(hashFunction.hashString(node.toString() + i));
   }
 }

 public T get(Object key) {
   if (circle.isEmpty()) {
     return null;
   }
   int hash = hashFunction.hashInt((Integer) key).asInt();
   if (!circle.containsKey(hash)) {
     SortedMap<Integer, T> tailMap = circle.tailMap(hash);
     hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
   }
   return circle.get(hash);
 }

 public static void main(String[] args) {
	 int numberOfReplicas = 10;
	 HashFunction hashFunction = Hashing.murmur3_128();
	 
	 Object obj=new Object();
	 List<String> nodd = new ArrayList<String>();
	 nodd.add("shard1");
	 nodd.add("shard2");
	 nodd.add("shard3");
	 
	 
	 ConsistentHash<String> ch =  new ConsistentHash<String>(hashFunction, numberOfReplicas, nodd); 
	 
	 ch.add("shard4");
	 ch.add("shard5");
	 ch.add("shard6");
	 
	 for (int i = 1; i<10;i++){
//		 synchronized (obj) {
			 System.out.println(i+ " : " + ch.get(i));	
//		}
		 	 
	 }
	 
	 ch.add("shard7");
	 System.out.println("----------------------------------------------");
	 for (int i = 1; i<10;i++){
//		 synchronized (obj) {
		   System.out.println(i+ " : " + ch.get(i));	 
//		 }
	 }
}
 
}